非类型模板参数有一些限制，只能是整型常量值(包括枚举)，指向对象/函数/成员的指针，指向对象或函数的左值引用，或者std::nullptr\_t(nullptr的类型)。

浮点数和类型对象不允许作为非类型模板参数:

\begin{lstlisting}[style=styleCXX]
template<double VAT> // ERROR: floating-point values are not
double process (double v) // allowed as template parameters
{
	return v * VAT;
}

template<std::string name> // ERROR: class-type objects are not
class MyClass { // allowed as template parameters
	...
};
\end{lstlisting}

当向指针或引用传递模板参数时，对象不能是字符串字面值、临时对象或数据成员和其他子对象。在C++17前，每个C++版本都放宽了这些限制，所以还有其他的限制:

\begin{itemize}
\item 
C++11中，对象必须具有外部链接。

\item 
C++14中，对象必须具有外部或内部链接。
\end{itemize}

因此，以下情况会报错:

\begin{lstlisting}[style=styleCXX]
template<char const* name>
class Message { // OK
	...
};

Message<"hello"> x; // ERROR: string literal "hello" not allowed
\end{lstlisting}

但也有解决方法(同样取决于C++的版本):

\begin{lstlisting}[style=styleCXX]
extern char const s03[] = "hi"; // external linkage
char const s11[] = "hi"; // internal linkage
int main()
{
	Message<s03> m03; // OK (all versions)
	Message<s11> m11; // OK since C++11
	static char const s17[] = "hi"; // no linkage
	Message<s17> m17; // OK since C++17
}
\end{lstlisting}

三种情况下，常量字符数组都由"hi"初始化，该对象用作用char const*声明的模板参数。若对象具有外部链接(s03)，这在所有C++版本中都有效;若对象具有内部链接(s11)，则在C++11和C++14中也是有效的;若对象没有链接，则需要C++17的支持。

请参阅第12.3.3节和第17.2节讨论了该领域在未来变化的可能。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{避免无效的表达式}

非类型模板参数可以是编译时表达式。例如:

\begin{lstlisting}[style=styleCXX]
template<int I, bool B>
class C;
...
C<sizeof(int) + 4, sizeof(int)==4> c;
\end{lstlisting}

但是，若在表达式中使用>，必须将整个表达式放入圆括号中，以便编译器确定>在哪里结束:

\begin{lstlisting}[style=styleCXX]
C<42, sizeof(int) > 4> c; // ERROR: first > ends the template argument list
C<42, (sizeof(int) > 4)> c; // OK
\end{lstlisting}











